/*
 * MiniSaveChooser.java
 *
 * Created on December 30, 2009, 3:32 PM
 */

package torchtools.gui;

import java.awt.Component;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.Vector;
import javax.swing.DefaultListModel;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.ListCellRenderer;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import torchtools.binary.TLPlayerSave;

/**
 * A file chooser specifically for Torchlight save files (SVT). 
 * 
 * @author  Matt
 */
public class SaveFileChooser extends javax.swing.JDialog {
    
    private final static String LIST_MSG = "{1} (Level {2} {0})";
    private final static String LIST_ERR_MSG = "Did not load '{0}' (Error) - {1}";
    private ToolContext context;
    private DefaultListModel model = new DefaultListModel();
    private boolean ok = false;
    
    public static final FilenameFilter SVT_FILTER = new FilenameFilter() {
        public boolean accept(File dir, String name) {
            return name.toLowerCase().endsWith(".svt");
        }
    };
    
    /** Creates new form MiniSaveChooser */
    public SaveFileChooser(ToolContext context) {
        super(context.getFrame(), true);
        this.context = context;
        initComponents();
        list.setCellRenderer(new TipCellRenderer());
        list.setModel(model);
        list.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                ListItem i = (ListItem)list.getSelectedValue();
                openBtn.setEnabled(i!=null);
            }
        });
        setLocationRelativeTo(context.getFrame());
        saveDirChanged();
    }
    
    public File showDialog() {
        ok = false;
        setVisible(true);
        ListItem li = (ListItem)list.getSelectedValue();
        return li!=null&&ok ? li.file : null;
    }
    
    /** Returns a {String, String, int, File} array with class, name, level and file. */
    public static Object[] preview(File path) throws IOException {
        TLPlayerSave save = new TLPlayerSave(path, "r", false);
        save.readPlayerInfo();
        save.close();
        return new Object[] {
                save.getPlayerClass(), 
                save.getPlayerName(),
                save.getLevel(),
                path };
    }
    
    public void saveDirChanged() {
        list.clearSelection();
        openBtn.setEnabled(false);
        model.clear();
        new ReadThread().start();
    }
    
    private class ReadThread extends Thread {
        public ReadThread() {
            setDaemon(true);
        }
        
        public void run() {
            File saveDir = context.getSaveDir();
            File[] saves = saveDir.listFiles(SVT_FILTER);
            Vector<ListItem> listData = new Vector<ListItem>(saves.length);
            for (File f : saves) {
                ListItem li;
                try {
                    Object[] o = preview(f);
                    li = new ListItem(o);
                }
                catch (IOException e) {
                    li = new ListItem(f, e);
                }
                add(li);
            }
        }
        
        private void add(final ListItem i) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    model.addElement(i);
                }
            });
        }
    }
    
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        openBtn = new javax.swing.JButton();
        jScrollPane1 = new javax.swing.JScrollPane();
        list = new javax.swing.JList();
        cancelBtn = new javax.swing.JButton();
        refreshBtn = new javax.swing.JButton();
        changeDir = new javax.swing.JButton();

        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        setTitle("Select Save");

        openBtn.setText("Open");
        openBtn.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                openBtnActionPerformed(evt);
            }
        });

        list.setModel(new javax.swing.AbstractListModel() {
            String[] strings = { "Wick the Cheat (Level 3 Alchemist)" };
            public int getSize() { return strings.length; }
            public Object getElementAt(int i) { return strings[i]; }
        });
        list.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
        list.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                listMouseClicked(evt);
            }
        });
        jScrollPane1.setViewportView(list);

        cancelBtn.setText("Cancel");
        cancelBtn.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                cancelBtnActionPerformed(evt);
            }
        });

        refreshBtn.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/refresh.png"))); // NOI18N
        refreshBtn.setToolTipText("Refresh list");
        refreshBtn.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                refreshBtnActionPerformed(evt);
            }
        });

        changeDir.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/open.png"))); // NOI18N
        changeDir.setText("Change Dir");
        changeDir.setToolTipText("Right-click to reset to default dir");
        changeDir.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                changeDirActionPerformed(evt);
            }
        });
        changeDir.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                changeDirMouseClicked(evt);
            }
        });

        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
                .addContainerGap()
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING)
                    .add(org.jdesktop.layout.GroupLayout.LEADING, jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 204, Short.MAX_VALUE)
                    .add(layout.createSequentialGroup()
                        .add(openBtn)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(cancelBtn))
                    .add(layout.createSequentialGroup()
                        .add(changeDir)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, 76, Short.MAX_VALUE)
                        .add(refreshBtn, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 23, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
                .addContainerGap()
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(refreshBtn, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 23, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                    .add(changeDir))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 170, Short.MAX_VALUE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(cancelBtn)
                    .add(openBtn))
                .addContainerGap())
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void changeDirMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_changeDirMouseClicked
        if (evt.getButton()==MouseEvent.BUTTON3) {
            File old = context.getSaveDir();
            context.resetSaveDir();
            if (!context.getSaveDir().equals(old))
                saveDirChanged();
        }
    }//GEN-LAST:event_changeDirMouseClicked

    private void changeDirActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_changeDirActionPerformed
        File dir = context.getSaveDir();
        JFileChooser jfc = context.getFileChooser(dir.getParent());
        int i = jfc.getFileSelectionMode();
        jfc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        if (jfc.showDialog(this, "Select") == JFileChooser.APPROVE_OPTION) {
            File f = jfc.getSelectedFile();
            if (f.isDirectory()) {
                if (!dir.equals(f)) {
                    context.setSaveDir(f);
                    saveDirChanged();
                }
            }
        }
        jfc.setFileSelectionMode(i);
    }//GEN-LAST:event_changeDirActionPerformed

    private void refreshBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_refreshBtnActionPerformed
        saveDirChanged();
    }//GEN-LAST:event_refreshBtnActionPerformed

    private void listMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_listMouseClicked
        if (evt.getClickCount()==2) {
            int i = list.getUI().locationToIndex(list, evt.getPoint());
            if (i!=-1 && list.getCellBounds(i, i).contains(evt.getPoint())) {
                list.setSelectedIndex(i);
                openBtnActionPerformed(null);
            }
        }
    }//GEN-LAST:event_listMouseClicked

    private void openBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openBtnActionPerformed
        ok = true;
        setVisible(false);
    }//GEN-LAST:event_openBtnActionPerformed

    private void cancelBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelBtnActionPerformed
        ok = false;
        setVisible(false);
    }//GEN-LAST:event_cancelBtnActionPerformed
    
    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); }
        catch (Exception e) {}
        
        final ToolContext ctx = new ToolContext() {
            private JFileChooser jfc =null;
            private File f;
            
            { 
                resetSaveDir();
            }
            
            public File getSaveDir() { return f; }
            public JFileChooser getFileChooser(String startDir) { 
                if (jfc==null) {
                    jfc = new JFileChooser(startDir);
                    jfc.setAcceptAllFileFilterUsed(true);
                    jfc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
                }
                return jfc;
            }
            public void resetSaveDir() {
                f = new File(System.getenv("APPDATA")+"\\runic games\\torchlight\\save");
            }
            public JFrame getFrame() {
                return null;
            }
            public void setSaveDir(File d) {
                f = d;
            }
        };
        
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                SaveFileChooser dialog = new SaveFileChooser(ctx);
                File save = dialog.showDialog();
                System.out.println(save);
            }
        });
    }
    
    private static class TipCellRenderer extends JLabel implements ListCellRenderer {
        
        public TipCellRenderer() {
            setOpaque(true);
        }

        public Component getListCellRendererComponent(
                       JList list,
                       Object value,
                       int index,
                       boolean isSelected,
                       boolean cellHasFocus) {
            ListItem i = ((ListItem)value);            
            setText(i.toString());
            setToolTipText(i.file.getName());
            
            if (isSelected) {
                setBackground(list.getSelectionBackground());
                setForeground(list.getSelectionForeground());
            } else {
                setBackground(list.getBackground());
                setForeground(list.getForeground());
            }
            return this;
        }
    }
    
    private static class ListItem {
        public final Object[] data;
        private String str;
        public final File file;
        public final IOException exc;
        
        public ListItem(File file, IOException exc) {
            this.exc = exc;
            this.data = null;
            this.file = file;
            this.str = MessageFormat.format(LIST_ERR_MSG, file.getName(),
                            exc.getMessage());
        }
        
        public ListItem(Object[] data) {
            this.data = data;
            this.exc = null;
            this.file = (File)this.data[3];
            this.str = MessageFormat.format(LIST_MSG, data);
        }
        
        public String toString() {
            return str;
        }
    }
    
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton cancelBtn;
    private javax.swing.JButton changeDir;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JList list;
    private javax.swing.JButton openBtn;
    private javax.swing.JButton refreshBtn;
    // End of variables declaration//GEN-END:variables
    
}
